/**
* @desc Performs form validation.  Part of the Codereck Javascript Suite.
*
* @copyright Ryan Zec 2007-2009, All Right Reserved
*
* @license BSD (see LICENSE file included, the generic templete can be found at http://www.opensource.org/licenses/bsd-license.php)
*/
(function($)
{
	//create the codereck scope
	$.cr = $.cr || {};

	//initialization of form validation
	$.fn.form_validation = function(options)
	{
		//add code here
		var form_validation = new $.cr.form_validation(this, options);
		$(this).data($.cr.form_validation.instance_key, form_validation);

		//return element to keep chaining alive
		return this;
	}

	//codereck form validation
	$.cr.form_validation = function(element, options)
	{
		var self = this;
		self.element = element;

		self.options = $.extend(
		{
			ajax: false,
			url: null,
			callback: function(){},
			invalid_class: 'cr_form_invalid',
			valid_class: 'cr_form_valid',
			rules: {},
			messages: {}
		}, options);

		//add the required functions on trigger of validate
		$(self.element).find('input').each(function()
		{
			var input_type = $(this).attr('type');

            if($(this).hasClass('cr_form_required'))
			{
				//validate event needs to be binded to all elements
				$(this).bind('validate', self.validate);

				switch(input_type)
				{
					case 'radio':
	                case 'checkbox':
						$(this).bind('click', self.validate);
						break;

					case 'text':
					case 'password':
	                    $(this).bind('keyup', self.validate);
						$(this).bind('blur', self.validate);
						break;

					default:
						break;
				}
			}
		});

		//set the default regex checks
		this.regex_names = new Array('email');
		this.regex_regexes = new Array(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
		this.regex_errors = new Array('Must be a valid email(example@example.com)');

		//set static members
		this.regex_prefix = 'cr_form_regex_';

		//validate textareas
		$(self.element).find('textarea').each(function()
		{
            if($(this).hasClass('cr_form_required'))
			{
				$(this).bind('validate', self.validate);
				$(this).bind('keyup', self.validate);
				$(this).bind('blur', self.validate);
			}
		});

		//validate select boxes
		$(self.element).find('select').each(function()
		{
            if($(this).hasClass('cr_form_required'))
			{
				$(this).bind('validate', self.validate);
				$(this).bind('change', self.validate);
				$(this).bind('blur', self.validate);
			}
		});


		//override the form submit event
		$(self.element).bind('submit', function(event)
		{
			var result = self.validate_form();

			//submit the form through ajax if configured to do so
			if(result === true && self.options.ajax === true)
			{
				event.preventDefault();

				if(self.options.url == null)
				{
					self.options.url = $(this).attr('action');
				}

				var method_type = $(this).attr('method');
				var form_data = $.cr.fn.form_to_data_object($(this).attr('id'));

				$.ajax(
				{
					url: self.options.url,
					type: method_type,
					data: form_data,
					success: self.options.callback
				});
			}

			return result;
		});
	}

	$.cr.form_validation.instance_key = 'codereck_form_validation_instance';
    $.cr.form_validation.get_instance = function(element)
    {
        return $(element).data($.cr.form_validation.instance_key);
    };

	$.extend($.cr.form_validation.prototype, $.cr.core);
	$.extend($.cr.form_validation.prototype,
	{
		validate: function()
		{
			var input_type = $(this).attr('type');
			var self = $.cr.form_validation.get_instance($(this).parents('form').slice(0,1));
			var regex_results = self.regex_check(this);

			switch(input_type)
			{
				case 'select-one':
				case 'textarea':
				case 'text':
				case 'password':
					if($(this).val() == '')
					{
						self.mark_invalid(this);
					}
					else if(regex_results !== true)
					{
						self.mark_invalid(this, regex_results);
					}
					else
					{
						var form_name = $(this).attr('name');
						var extra_rules = self.options.rules[form_name];
						var message = 'Form validation error';

						//check any extra rules that have been set

						if(extra_rules != undefined && extra_rules != undefined)
						{
							if(extra_rules.matching != undefined && extra_rules.matching != null)
							{
								message = 'This field must matching it\'s matching field';

								if(extra_rules.matching_message != undefined && extra_rules.matching_message != null)
								{
									message = extra_rules.matching_message;
								}

								self.options.rules[extra_rules.matching] =
								{
									matching: form_name,
									matching_message: message
								};

								if($(self.element).find('[name=' + extra_rules.matching + ']').slice(0,1).val() != $(this).val())
								{
									$(self.element).find('[name=' + extra_rules.matching + ']').slice(0,1).bind('keyup', self.validate);
									$(self.element).find('[name=' + extra_rules.matching + ']').slice(0,1).bind('blur', self.validate);
									self.mark_invalid(this, message);
									self.mark_invalid($(self.element).find('[name=' + extra_rules.matching + ']').slice(0,1), message);
									break;
								}
								else
								{
									self.mark_valid($(self.element).find('[name=' + extra_rules.matching + ']').slice(0,1));
									self.mark_valid(this);
									break;
								}
							}

							if(extra_rules.min_length != undefined && extra_rules.min_length != null)
							{
								message = 'This field must have at least ' + extra_rules.min_length + ' characters';

								if(extra_rules.min_length_message != undefined && extra_rules.min_length_message != null)
								{
									message = extra_rules.matching_message;
								}

                                if($(this).val().length < extra_rules.min_length)
								{
									self.mark_invalid(this, message);
									break;
								}
							}

							if(extra_rules.max_length != undefined && extra_rules.max_length != null)
							{
								message = 'This field can not exceed ' + extra_rules.max_length + ' characters';

								if(extra_rules.max_length_message != undefined && extra_rules.max_length_message != null)
								{
									message = extra_rules.matching_message;
								}

                                if($(this).val().length > extra_rules.max_length)
								{
									self.mark_invalid(this, message);
									break;
								}
							}
						}

						self.mark_valid(this);
					}
					break;

				case 'radio':
				case 'checkbox':
					var input_name = $(this).attr('name');

					//alert('input[name=' + input_name + ']:checked');

                    if($('input[name=' + input_name + ']:checked').length === 1)
					{
						self.mark_valid(this);
					}
					else
					{
						self.mark_invalid(this);
					}
					break;
			}
		},

		validate_form: function()
		{
			var options = this.options;

			$(self.element).find('input').each(function()
			{
				$(this).trigger('validate');
			});

			$(self.element).find('select').each(function()
			{
				$(this).trigger('validate');
			});

			$(self.element).find('textarea').each(function()
			{
				$(this).trigger('validate');
			});

			if($(this.element).find('.cr_form_invalid').length > 0)
			{
				return false;
			}
			else
			{
				return true;
			}
		},

		mark_invalid: function(element, custom_message)
		{
			var options = this.options;
			var message = 'This field is required';

			if($(element).attr('title'))
			{
				if($(element).attr('title').length > 0)
				{
					message = $(element).attr('title');
				}
			}

			if(custom_message != undefined && custom_message != null)
			{
				message = custom_message;
			}

            $(element).removeClass(options.valid_class);
			$(element).parent().children('.' + options.valid_class + '_text').remove();

			$(element).addClass(options.invalid_class);

			//if($(element).parent().children('.' + options.invalid_class + '_text').length == 0)
			//{
				$(element).parent().children('.' + options.invalid_class + '_text').remove();
				$(element).parent().append('<span class="' + options.invalid_class + '_text ' + $(element).attr('name') + '">' + message + '</span>');
			//}
		},

		mark_valid: function(element)
		{
			var options = this.options;

			$(element).removeClass(options.invalid_class);
			$(element).parent().children('.' + options.invalid_class + '_text').remove();

			if($(element).hasClass('cr_form_show_valid'))
			{
				$(element).addClass(options.valid_class);

				if($(element).parent().children('.' + options.valid_class + '_text').length == 0)
				{
					$(element).parent().append('<span class="' + options.valid_class + '_text ' + $(element).attr('name') + '">Valid</span>');
				}
			}
		},

		regex_check: function(element)
		{
			var passed = false;
			var fail_regex = 0;
			var regex = new RegExp('');

			var length = this.regex_names.length;
			var class_name = '';

			for(x = 0; x < length; x++)
			{
				class_name = this.regex_prefix + this.regex_names[x];
				if($(element).hasClass(class_name))
				{
					regex = this.regex_regexes[x];
					fail_regex = x;
					break;
				}
			}

			if(passed != true)
			{
				passed = regex.test($(element).val());
			}

			if(passed === true)
			{
				return true;
			}
			else
			{
				return this.regex_errors[fail_regex];
			}

			return passed;
		},

		add_regex: function(name, regex, error)
		{
			if(name && regex && error)
			{
				this.regex_names.push(name);
				this.regex_regexes.push(regex);
				this.regex_errors.push(error);
			}
		}
	});
})(jQuery);